﻿#pragma once

#include "geom_curve.h"

namespace CAGD
{

/**
 * 贝塞尔曲线.
 */
template <int Dim> class GeomBezierCurveDim : public GeomCurveDim<Dim>
{
  public:
    /**
     * @brief 基本构造函数.
     * @param cpts
     * @see
     */
    GeomBezierCurveDim(const std::vector<BPntN<Dim>> &cpts) : m_cpts(cpts), m_weights(cpts.size(), 1)
    {
    }

    /**
     * @brief 有理构造函数.
     * @param cpts
     * @param weights
     * @see
     */
    GeomBezierCurveDim(const std::vector<BPntN<Dim>> &cpts, const std::vector<double> &weights)
        : m_cpts(cpts), m_weights(weights)
    {
    }

    /**
     * @brief 返回控制点.
     * @return
     * @see
     */
    const std::vector<BPntN<Dim>> &Poles() const
    {
        return m_cpts;
    }

    /**
     * @brief 设置控制点.
     * @param cpts
     * @see
     */
    void SetPoles(const std::vector<BPntN<Dim>> &cpts)
    {
        m_cpts = cpts;
    }

    /**
     * @brief 控制点数量.
     * @return
     * @see
     */
    int NbPoles() const
    {
        return m_cpts.size();
    }

    /**
     * @brief 次数.
     * @return
     * @see
     */
    int Degree() const
    {
        return m_cpts.size() - 1;
    }

    /**
     * @brief 起始参数.
     * @return
     * @see
     */
    double FirstParameter() const override
    {
        return 0.0;
    }

    /**
     * @brief 终止参数.
     * @return
     * @see
     */
    double LastParameter() const override
    {
        return 1.0;
    }

    /**
     * @brief 取值函数.
     * @param t
     * @param P
     * @see
     */
    void D0(double t, BPntN<Dim> &P) const override
    {
        // 转齐次坐标
        int n = m_cpts.size();
        std::vector<BPntN<Dim + 1>> ps;
        for (int i = 0; i < n; i++)
        {
            ps.push_back(cartesian_to_homogenous(m_cpts[i]));
            ps.back()[Dim] = m_weights[i];
        }

        for (int r = 1; r < n; r++)
            for (int j = 0; j < n - r; j++)
                ps[j] = combine(ps[j], ps[j + 1], 1 - t, t);
        P = homogenous_to_cartesian(ps.front());
    }

    /**
     * @brief 求切向.
     * @param t
     * @param P
     * @param V1
     * @see
     */
    void D1(double t, BPntN<Dim> &P, BVecN<Dim> &V1) const override
    {
    }

    /**
     * @brief 求 2 阶导.
     * @param t
     * @param P
     * @param V1
     * @param V2
     * @see
     */
    void D2(double t, BPntN<Dim> &P, BVecN<Dim> &V1, BVecN<Dim> &V2) const override
    {
    }

    /**
     * @brief 求 n 阶导.
     * @param N
     * @param t
     * @param P
     * @param V
     * @see
     */
    void DN(int N, double t, BPntN<Dim> &P, std::vector<BVecN<Dim>> &V) const override
    {
    }

    /**
     * @brief 引用必要的控制点.
     * @return
     * @see
     */
    std::vector<BPntN<Dim> *> MakeReference() override
    {
        std::vector<BPntN<Dim> *> reference;
        for (int i = 0; i < m_cpts.size(); i++)
            reference.push_back(&m_cpts[i]);
        return reference;
    }

  protected:
    std::vector<BPntN<Dim>> m_cpts;
    std::vector<double> m_weights;
};

using Geom2dBezierCurve = GeomBezierCurveDim<2>;
using GeomBezierCurve = GeomBezierCurveDim<3>;

} // namespace CAGD
